/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFMixedOfflineSource
  \brief to process Mixed offline data
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-04
  \date 2021-12-15 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-04   <td>Asia Sun    <td>file created                  </tr>
  <tr>  <td>2021-10-13   <td>Asia Sun    <td>completing                    </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <string>
#include <iostream>
#include <unistd.h>
#include "FairRootManager.h"
#include "FairSink.h"
#include "ETFMixedOfflineSource.h"
#include "ETFPXIUnpacker.h"
#include "ETFVMEUnpacker.h"
#include "ETFMsg.h"

using std::cout;
using std::endl;
using std::flush;
using std::string;

ClassImp(ETFMixedOfflineSource);

ETFMixedOfflineSource::ETFMixedOfflineSource(const string &pxifile, const string &vmefile)
    : ETFOfflineSource(), fPXIUnpacker(nullptr), fVMEUnpacker(nullptr){
  SetType(SourceType::kMIXEDSOURCE);
  if("" != pxifile){
    if(IsPXIFileName(pxifile)) fPXIFileName = pxifile;
    if(IsVMEFileName(pxifile)) fVMEFileName = pxifile;
  } // end if
  if("" != vmefile){
    if(IsPXIFileName(vmefile)) fPXIFileName = vmefile;
    if(IsVMEFileName(vmefile)) fVMEFileName = vmefile;
  } // end if
  if("" == fPXIFileName) ETFMsg::Error("ETFMixedOfflineSource", "ctor: pxi file name not set");
  if("" == fVMEFileName) ETFMsg::Error("ETFMixedOfflineSource", "ctor: vme file name not set");

  // echo printing //
  cout << "The input PXI file is \033[32;1m" << fPXIFileName << "\033[0m" << endl;
  cout << "The input VME file is \033[32;1m" << fVMEFileName << "\033[0m\n" << endl;

  if(access(fPXIFileName.Data(), F_OK))
    ETFMsg::Error("ETFMixedOfflineSource", "ctor: PXI file %s not exists", fPXIFileName.Data());
  if(access(fVMEFileName.Data(), F_OK))
    ETFMsg::Error("ETFMixedOfflineSource", "ctor: VME file %s not exists", fVMEFileName.Data());
} // end ctor

void ETFMixedOfflineSource::SetPXIDataFile(const string &file){
  if(IsPXIFileName(file, true)) fPXIFileName = file;
  else ETFMsg::Error("ETFMixedOfflineSource", "SetPXIDataFile: invalid file name: %s", file);
} // end member function SetPXIDataFile
void ETFMixedOfflineSource::SetVMEDataFile(const string &file){
  if(IsPXIFileName(file, true)) fVMEFileName = file;
  else ETFMsg::Error("ETFMixedOfflineSource", "SetVMEDataFile: invalid file name: %s", file);
} // end member function SetVMEDataFile

/// generate a file name for the output root
const TString ETFMixedOfflineSource::ROOTFileName() const{
  char name[256]; strcpy(name, fPXIFileName.Data());
  return TString(basename(name))+"_"+ETFMsg::time0(1)+"_MIXED.root";
} // end member function ROOTFileName

// unpackers would have been deleted upon reaching this dtor,
// so don't bother deleting them AGAIN
ETFMixedOfflineSource::~ETFMixedOfflineSource(){}

/// open the file, would be called by FairRoot:
/// run->Init()=>fRootManager->Init()=>fSource->Init()
bool ETFMixedOfflineSource::Init(){
  FILE *fpPXI, *fpVME;
  if(!(fpPXI = fopen(fPXIFileName, "rb"))){
    remove(ROOTFileName().Data());
    ETFMsg::Error("ETFMixedOfflineSource", "Init: Failed to open input PXI data file %s", fPXIFileName.Data());
  } // end if
  if(!(fpVME = fopen(fVMEFileName, "rb"))){
    remove(ROOTFileName().Data());
    ETFMsg::Error("ETFMixedOfflineSource", "Init: Failed to open input VME data file %s", fVMEFileName.Data());
  } // end if

  for(const auto &obj: *fUnpackers){
    ETFUnpacker *unpacker = dynamic_cast<ETFUnpacker *>(obj);
    if(!unpacker) ETFMsg::Error("ETFMixedOfflineSource", "Init: a null unpacker encountered");
    if(unpacker->GetType() == 0){
      fPXIUnpacker = dynamic_cast<ETFPXIUnpacker *>(unpacker);
      fMap[unpacker] = fpPXI;
    } // end if(pxi)
    if(unpacker->GetType() == 1){
      fVMEUnpacker = dynamic_cast<ETFVMEUnpacker *>(unpacker);
      fMap[unpacker] = fpVME;
      fVMEUnpacker->ReadComment(fpVME); // skip the comment
    } // end if(vme)
  } // end for over unpackers

  if(fMap.size() != 2) ETFMsg::Error("ETFMixedOfflineSource", "Init: fMap.size() != 2");
  auto it = fMap.begin();
  if(it->second == (++it)->second) ETFMsg::Error("ETFMixedOfflineSource", "Init: same FILE values");

  return true;
} // end member function Init

void ETFMixedOfflineSource::FinishEvent(){
  cout << "Processing PXI event " << fPXIUnpacker->GetCurrentEventIndex()
       << " || VME block " << fVMEUnpacker->GetBlockIndex()
       << " VME event " << fVMEUnpacker->GetCurrentEventIndex() << "\r" << flush;
} // end member function FinishEvent

void ETFMixedOfflineSource::PrintSummary(){
  ETFMsg::Logo();
  fPXIUnpacker->PrintSummary();
  fVMEUnpacker->PrintSummary();

  cout << "------------- EVENT NUMBER DIFFERENCE -------------" << endl;
  cout << "\033[36;1mPXI ev_cnt - VME ev_cnt: \033[31;1m";
  cout << fPXIUnpacker->GetNofProcessedEvent() - fVMEUnpacker->GetNofProcessedEvent();
  cout << "\033[0m\n" << endl;
  cout << "\033[45;1m .... .... ... RAW MIXED DATA DECODEING HAS BEEN COMPLETED .... .... ... \033[0m\n\n\n" << endl;

  cout << "\033[33;1m:)\033[0m Unpacked data have been written into ";
  cout << "\033[1m" << FairRootManager::Instance()->GetSink()->GetFileName().Data();
  cout << " \033[33;1m:)\033[0m.\n";
} // end member function PrintSummary
